19 使用静态分析器

说明:Xcode 3.2开始加入的新功能,不需要运行程序就可以从逻辑上检测代码的工具,它可以寻找会演变成bug的错误。

19.1 静态工作

说明:静态分析器可以识别以下几种错误

  • 安全问题:比如内存泄漏和缓冲区溢出
  • 并发性问题:比如静态条件(也就是依赖时间的两个或多个任务失效)
  • 逻辑问题:包括废代码和不好的编码习惯

注意:静态分析器存在以下不足

  • 拖慢构建程序的过程:因为需要消耗时间来进行分析
  • 有时会误报错误
  • 需要适应:因为改变了熟悉的工作流程

19.1.1 开始分析

运行静态分析器:Product(菜单) -> Analyze,分解决过在导航栏issue中可以看到
Alt text

19.1.1.1 废代码

废代码:创建了一个对象pool,但从没有在代码中直接访问过,没有向它发送消息也没有更改过它。
优化手段:移除废代码
优化意义:废代码并不一定会给程序带来功能上的问题,但终归会浪费性能,移除废代码可以使应用程序更加高效。

Alt text

19.1.1.2 内存泄漏:对象被释放之前程序return

说明:通常还没有释放掉分配的内存的对象,就过早返回时便会出现这种情况。
扩展:可以通过点击带有分析器图标的代码来观察代码从开始到当前行的运行流程

  1. 触发“运行流程”
    Alt text
  2. 完毕
    Alt text

19.1.1.3 内存泄漏:副本没有释放

说明:创建一个对象的副本,要在适当的时候对其进行释放,否则引发内存泄漏。
优化手段:main函数结尾处释放carCopy
Alt text

19.1.1.4 内存泄漏:description方法中的desc在返回前没有释放

说明:AllWeatherRadial类中的description方法中分配了一个字符串desc,但没有在返回函数之前释放它。

1
2
3
4
5
6
7
8
9
10
11
12
- (NSString *) description
{
NSString *desc;
desc = [[NSString alloc] initWithFormat:
@"AllWeatherRadial: %.1f / %.1f / %.1f / %.1f",
[self pressure], [self treadDepth],
[self rainHandling],
[self snowHandling]];

return [desc autorelease];

} // description

19.1.2 协助分析器

说明:静态分析器分析出的“问题”如果是我们有意的,可以通过在声明方法时使用一些关键字避免误报;或者有些情况下,想要使通常没问题的方式发出警报。比如

关键字 用途 对应的惯例 返回对象为Core Foundation对象时
NS_RETURNS_RETAINTED 标记方法,以返回一个保留计数器的值不是零的对象 分配内存的地方也要负责清理内存 CF_RETURNS_RETAINTED
NS_RETURNS_NOT_RETAINED 使静态分析器在方法试图返回一个保留对象时发出issue 返回保留对象通常不需要做额外内存管理 NS_RETURNS_NOT_RETAINED
CLANG_ANALYZER_NORETURN 如果方法有值返回,就在静态分析是发出警报 方法返回值不会发生issue 无意义

NS_RETURNS_RETAINTED:返回一个保留的对象

1
- (NSMutableArray *) superDuperArrayCreator NS_RETURNS_RETAINED;
1
2
3
4
5
6
7
- (NSMutableArray *) superDuperArrayCreator
{
NSMutableArray *myArray = [[NSMutableArray alloc] init];
// ...
// 没将 myArray 释放就返回了
return myArray;
}

NS_RETURNS_NOT_RETAINED:返回一个未保留的对象

1
2
// 分析器会在该方法视图返回一个保留对象时提出issue
- (NSMutableArray *) superDuperArrayCreator NS_RETURNS_NOT_RETAINED;

19.1.3 了解更多

说明:静态分析器能够找到的其它问题

issue 说明 解决issue
等号错误 if (myValue = expression)存在歧义 赋值后判空:if ((myValue = expression));判等:if (nil != (myValue = expression))
内存泄漏 方法中的运行时错误使方法提前return,导致release代码没有执行而发生内存泄漏 无论什么时候退出了方法,都需要确认有没有分配了单海没有释放的对象
过度释放 重复autorelease 移除多余的autorelease
@synchronized语句中的空值 @synchronized(object)中的object如果为nil就发出issue 确保object不为nil

建议:静态分析器作为一个善意但烦人的朋友,因为它所说的通常都是对的。
注意:不要太依赖静态分析器来查找每一个内存泄漏和废代码,自己要对自己的代码负责。

19.2 小结